﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EnvDTE;
using EnvDTE80;
using System.Reflection;
using System.IO;

namespace BaseAddIn.Analysis
{
    public sealed class AddIn : Base
    {
        #region Campos

        private List<Rules.BaseRuleAddIn> _selectedRulesAddin;
        private List<string> _dontAnalyseChildrenList;       

        #endregion

        #region Construtor

        public AddIn(List<Rules.BaseRuleAddIn> selectedRulesAddin)
            : base()
        {
            _selectedRulesAddin = selectedRulesAddin;

            _dontAnalyseChildrenList = new List<string>();
            _dontAnalyseChildrenList.Add("Properties");
            _dontAnalyseChildrenList.Add("Service References");
        }

        #endregion

        #region Public Methods

        public sealed override void Analise(Project projetoAnalisar)
        {
            string filePath = null;

            try
            {
                filePath = Path.Combine(projetoAnalisar.Properties.Item("FullPath").Value.ToString(),
                                        projetoAnalisar.Properties.Item("FileName").Value.ToString());

                for(int countRule =0; countRule < _selectedRulesAddin.Count; countRule++)
                {
                    _selectedRulesAddin[countRule].IniciaAnalise();
                    _selectedRulesAddin[countRule].Check(projetoAnalisar, filePath);
                }

                for (int i = 1; i <= projetoAnalisar.ProjectItems.Count; i++)
                {
                    AnalisaProjectItem(projetoAnalisar.ProjectItems.Item(i));
                }
            }
            catch
            {
                throw;
            }
            finally
            {
                for (int countRule = 0; countRule < _selectedRulesAddin.Count; countRule++)
                {
                    ListaProblemas.AddRange(_selectedRulesAddin[countRule].FinalizaAnalise());
                    _selectedRulesAddin[countRule].ResetaStatusAnalise();
                }
            }
        }

        #endregion

        #region Private Methods

        private void AnalisaProjectItem(ProjectItem item)
        {
            FileCodeModel2 fileCode = null;
            CodeElement2 codeElement = null;
            CodeNamespace codeNamespace = null;
            CodeClass2 classe = null;
            CodeInterface2 inter = null;
            string filePath = null;

            filePath = item.Properties.Item("FullPath").Value.ToString();

            for (int countRule = 0; countRule < _selectedRulesAddin.Count; countRule++)
            {
                _selectedRulesAddin[countRule].Check(item, filePath);
            }

            if (item.FileCodeModel != null)
            {
                fileCode = (FileCodeModel2)item.FileCodeModel;

                if (fileCode.CodeElements != null)
                {
                    for (int countCodeElements = 1; countCodeElements <= fileCode.CodeElements.Count; countCodeElements++)
                    {
                        codeElement = (CodeElement2)fileCode.CodeElements.Item(countCodeElements);

                        for (int countRule = 0; countRule < _selectedRulesAddin.Count; countRule++)
                        {
                            _selectedRulesAddin[countRule].Check(codeElement, filePath);
                        }

                        if (codeElement.Kind == vsCMElement.vsCMElementNamespace
                            && codeElement.Children != null)
                        {
                            codeNamespace = (CodeNamespace)codeElement;

                            for (int countRule = 0; countRule < _selectedRulesAddin.Count; countRule++)
                            {
                                _selectedRulesAddin[countRule].Check(codeNamespace, filePath);
                            }

                            for (int countCodeChildren = 1; countCodeChildren <= codeNamespace.Children.Count; countCodeChildren++)
                            {
                                if (codeNamespace.Children.Item(countCodeChildren).Kind == vsCMElement.vsCMElementClass)
                                {
                                    classe = (CodeClass2)codeNamespace.Children.Item(countCodeChildren);

                                    AnalisaClasse(classe, codeNamespace, filePath);
                                }
                                else if (codeNamespace.Children.Item(countCodeChildren).Kind == vsCMElement.vsCMElementInterface)
                                {
                                    inter = (CodeInterface2)codeNamespace.Children.Item(countCodeChildren);

                                    for (int countRule = 0; countRule < _selectedRulesAddin.Count; countRule++)
                                    {
                                        _selectedRulesAddin[countRule].Check(inter, filePath);
                                    }
                                }
                            }
                        }
                    }
                }

                if (item.ProjectItems != null)
                {
                    for (int countProjectItems = 1; countProjectItems <= item.ProjectItems.Count; countProjectItems++)
                    {
                        AnalisaProjectItem(item.ProjectItems.Item(countProjectItems));
                    }
                }
            }
            else if (!_dontAnalyseChildrenList.Contains(item.Name))
            {
                if (item.ProjectItems != null)
                {
                    for (int countProjectItems = 1; countProjectItems <= item.ProjectItems.Count; countProjectItems++)
                    {
                        AnalisaProjectItem(item.ProjectItems.Item(countProjectItems));
                    }
                }
            }
        }

        private void AnalisaClasse(CodeClass2 classe, CodeNamespace namespaceElement, string filePath)
        {
            List<CodeInterface2> listaInterfaces = new List<CodeInterface2>();
            List<CodeClass2> listaClasse = new List<CodeClass2>();

            CodeElement2 aux;
            CodeFunction codeFunction;
            CodeProperty codeProperty;
            CodeVariable codeVariable;
            CodeEnum codeEnum;

            if (!classe.StartPoint.Parent.Parent.FullName.Contains(".Designer."))
            {
                for (int countRule = 0; countRule < _selectedRulesAddin.Count; countRule++)
                {
                    _selectedRulesAddin[countRule].Check(classe, filePath);
                }

                for (int countClassChildren = 1; countClassChildren <= classe.Children.Count; countClassChildren++)
                {
                    aux = (CodeElement2)classe.Children.Item(countClassChildren);

                    if (aux.Kind == vsCMElement.vsCMElementFunction)
                    {
                        codeFunction = (CodeFunction)aux;
                        for (int countRule = 0; countRule < _selectedRulesAddin.Count; countRule++)
                        {
                            _selectedRulesAddin[countRule].Check(codeFunction, namespaceElement, classe, filePath);
                        }
                    }
                    else if (aux.Kind == vsCMElement.vsCMElementVariable)
                    {
                        codeVariable = (CodeVariable)aux;
                        for (int countRule = 0; countRule < _selectedRulesAddin.Count; countRule++)
                        {
                            _selectedRulesAddin[countRule].Check(codeVariable, namespaceElement, classe, filePath);
                        }
                    }
                    else if (aux.Kind == vsCMElement.vsCMElementProperty)
                    {
                        codeProperty = (CodeProperty)aux;
                        for (int countRule = 0; countRule < _selectedRulesAddin.Count; countRule++)
                        {
                            _selectedRulesAddin[countRule].Check(codeProperty, namespaceElement, classe, filePath);
                        }
                    }
                    else if (aux.Kind == vsCMElement.vsCMElementEnum)
                    {
                        codeEnum = (CodeEnum)aux;
                        for (int countRule = 0; countRule < _selectedRulesAddin.Count; countRule++)
                        {
                            _selectedRulesAddin[countRule].Check(codeEnum, namespaceElement, classe, filePath);
                        }
                    }
                    else if (aux.Kind == vsCMElement.vsCMElementInterface)
                    {
                        listaInterfaces.Add((CodeInterface2)aux);
                    }
                    else if (aux.Kind == vsCMElement.vsCMElementClass)
                    {
                        listaClasse.Add((CodeClass2)aux);
                    }
                }

                for (int i = 0; i < listaInterfaces.Count; i++)
                {
                    for (int countRule = 0; countRule < _selectedRulesAddin.Count; countRule++)
                    {
                        _selectedRulesAddin[countRule].Check(listaInterfaces[i], filePath);
                    }
                }

                for (int i = 0; i < listaClasse.Count; i++)
                {
                    AnalisaClasse(listaClasse[i], namespaceElement, filePath);
                }
            }
        }

        #endregion

        #region IDisposable Members

        public new void Dispose()
        {
            if (_selectedRulesAddin != null)
                _selectedRulesAddin.Clear();

            _selectedRulesAddin = null;

            if (_dontAnalyseChildrenList != null)
                _dontAnalyseChildrenList.Clear();

            _dontAnalyseChildrenList = null;

            base.Dispose();
        }

        #endregion
    }
}
